/**
 * @author 陈泰来
 * @version V1.0
 * @Project echo-java-base
 * @Title
 * @Description 双向链表LinkedHashMap和synchronized结合
 * @Package concurrent.blockingQueue.bqtest3
 * @date 2021/3/22 4:13 下午
 * @Copyright:学如逆水行舟，不进则退 .
 */
package concurrent.blockingQueue.bqtest3;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

public class BQTestQueue3<T> {

    public static final int EMPTY_QUEUE_SIZE = 0;

    private Integer index = 0;

    private final static Integer MAX_QUEUE_SIZE = 50;

    //队列缓冲区
    LinkedHashMap<Integer, T> queue;


    public BQTestQueue3(LinkedHashMap<Integer, T> queue) {
        this.queue = new LinkedHashMap<>();
        this.queue = queue;
    }

    /**
     * @return void
     * @author chentl
     * @description 同步方法 向缓冲区推送消息
     * @date 2021/3/22 4:25 下午
     * @params [msg]
     */
    public final synchronized void push(T msg) throws InterruptedException {

        while (!(queue.size() < MAX_QUEUE_SIZE)) wait();

        queue.put(index, msg);
        System.out.printf("下标为 %d 的消息: 【%s】 已入队,当前队列大小为: %d \n", index, msg, queue.size());

        //recalculation index
        int curIndex = index + 1;
        index = curIndex >= MAX_QUEUE_SIZE ? curIndex % MAX_QUEUE_SIZE : curIndex;

        notifyAll();
    }

    /**
     * @return void
     * @author chentl
     * @description 同步方法 消费消息
     * @date 2021/3/22 4:38 下午
     * @params []
     */
    public final synchronized void take() throws InterruptedException {

        while (queue.size() == EMPTY_QUEUE_SIZE) wait();


        //循环队列 移除元素

        Iterator<Map.Entry<Integer, T>> iterator = queue.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, T> entry = iterator.next();
            int index = entry.getKey();

            iterator.remove();
            System.out.printf("消费下标为: %d 的元素： %s \n", index, entry.getValue());

        }

        notifyAll();
    }

    public static void main(String[] args) {
        BQTestQueue3<String> bqTestQueue3 = new BQTestQueue3<>(new LinkedHashMap<>());
        Thread consumer = new Thread(new Consumer(bqTestQueue3));
        Thread producer = new Thread(new Producer(bqTestQueue3));

        consumer.start();
        producer.start();

    }

}
